/*###################################################################
 *
 * LeeKweed - Liquid, A water ripple rendering program
 *
 * Copyright (c) 2008-2009, Xiaoyong Guo
 *
 *
 * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 *
 *
 * mailto: guo.xiaoyong@gmail.com
 *         http://www.wordeazy.com
 *
 *
 *##################################################################*/


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>


#include <SDL/SDL.h>
#include <heightmap.h>
#include <tcimg.h>

const char WndCaption[] = "LeeKweed VERSION 0.3";
const char MBContent[] =
    "LeeKweed is a small program simulating water ripples on a 2D surface. \n\
You are about to see a picture, just left click the picture to make ripples.\n\
There are four pictures in this program. You can add paramters 1, 2, \n\
3 or 4 to choose a picture. The fern picture is generated by my another \n\
small program FracErn. It is a classic example of fractal images.\n\n\
The word LeeKweed is a wrong spelling of the english word LIQUID. \n\
there's no particular reason why I chose this name.\n\n\
The source code can be downloaded from my website http://www.wordeazy.com \n\
(another wrong spelling). There is a console version of this prgram \n\
called ConLeeKweed. It only produces a series of BMP files. There are \n\
some tools like convert from ImageMagick (Magick\?\?, yes) can convert them \n\
into an animated GIF file.\n\n\
LeeKweed was written by Guo Xiaoyong, a programming enthusiast.\n \
Feel free to send me email if you have any questions about this program.\n\
My email address is guo.xiaoyong@gmail.com. \n\n\
Click OK to continue...";


//#define __NEEDDELAY__
Uint32 DELAYTIME = 10;


#if SDL_BYTEORDER == SDL_BIG_ENDIAN
Uint32 rmask = 0xff000000;
Uint32 gmask = 0x00ff0000;
Uint32 bmask = 0x0000ff00;
Uint32 amask = 0x000000ff;
#else
Uint32 rmask = 0x000000ff;
Uint32 gmask = 0x0000ff00;
Uint32 bmask = 0x00ff0000;
Uint32 amask = 0xff000000;
#endif


/*#################################################################
 *
 * Main Function
 *
 *################################################################*/

int main(int argc, char *argv[])
{
    /* set up 4 images used in this program,
     * TCBG stands for True Color BackGround */
    extern const TrueColorImage TCBGImage;
    const char MODE = 'N';


    int MouseClickFlag = 0;

    Uint16 Mouse_X = 100;
    Uint16 Mouse_Y = 100;

    int i, j;
    int dx, dy, x, y, info;
    int Drop_x, Drop_y;

    /* for manipulating pixels */
    Uint8 *PixBuf_BGImage;
    Uint8 *PixBuf_Screen;

    SDL_Surface *Screen;
    SDL_Surface *BGImage;
    SDL_Rect     dest;
    HeightMap    hm;

    /* end of setting up all the variables */
    /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#if 0
    /* show up a MessageBox if the program is compiled for windows */
#ifdef _WIN32
#include <windows.h>
    MessageBox(NULL, MBContent, WndCaption, MB_OK);
#endif
#endif

    /* set up the randseed */
    srand(time(NULL));

    /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
     *
     * 1. Initialize SDL
     * 2. Create a surface
     * 3. set up the Rectangular
     * 4. set up the video mode (24bit)
     * 5. change the default window caption
     * 6. initialize HeighMap which is needed for rendering
     * 7. register SDL_Quit
     *
     *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

    if ( SDL_Init( SDL_INIT_VIDEO)  < 0 )
    {
        fprintf(stderr, "Unable to initialize SDL: %s\n",
                SDL_GetError());

        exit(1);
    }


    /* create SDL Surface from image data */
    BGImage
    = SDL_CreateRGBSurfaceFrom(TCBGImage.ImgData,
                               TCBGImage.ImgWidth,
                               TCBGImage.ImgHeight,
                               24,
                               TCBGImage.ImgByteWidth,
                               rmask, gmask,
                               bmask, amask);

    if ( BGImage == NULL )
    {
        fprintf(stderr, "Cannot Create Image: %s\n",
                SDL_GetError());

        exit(2);
    }


    /* get the size of the background image
     * set up the window size accordingly  */
    dest.x = 0;
    dest.y = 0;
    dest.w = BGImage->w;
    dest.h = BGImage->h;

    /* set video mode */
    Screen
    = SDL_SetVideoMode( BGImage->w, BGImage->h,
                        BGImage->format->BitsPerPixel,
                        SDL_SWSURFACE);


    if ( Screen == NULL )
    {
        fprintf(stderr, "Unable to set video mode: %s\n",
                SDL_GetError());

        exit(3);
    }


    /* change the caption */
    SDL_WM_SetCaption(WndCaption, NULL);


    /* Initialize the HeightMap */
    info = HeightMap_Init(&hm, (int)BGImage->w,
                          (int)BGImage->h);

    if (info != 0)
    {
        fprintf(stderr, "Unable to initialize HeightMap!!\n");

        exit(4);
    }

    atexit(SDL_Quit);

    /* end of setting up of the devices */


    /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
     *
     * Enter into the while loop which do all the rendering
     * and message processing stuff
     *
     *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

    /* MouseClickFlag must set to be 0 initially */
    MouseClickFlag = 0;
    Mouse_X = 100;
    Mouse_Y = 100;

    while (1)
    {
        /* if mouse clikc event has been detected */
        if (MouseClickFlag)
        {
            for (i = -2; i < 2; ++i)
            {
                for (j = -2; j < 2; ++j)
                {
                    SetPrevHMValue(&hm, Mouse_X, Mouse_Y+j, -200);
                }
            }

            MouseClickFlag = 0;
        }
        /* other randomly generate raindrops */
        else if (rand()%30 < 4)
        {
            Drop_x = rand()%BGImage->w;
            Drop_y = rand()%BGImage->h;

            for (i = -2; i < 2; ++i)
            {
                for (j = -2; j < 2; ++j)
                {
                    SetPrevHMValue(&hm, Drop_x+i,
                                   Drop_y+j, -200);
                }
            }
        }

        HeightMap_Next(&hm);
        HeightMap_PreRendering(&hm);


	/* Draw the image onto Screen */
        info = SDL_LockSurface(Screen);

        if ( info == -1 )
        {
            fprintf(stderr, "Screen cannot be locked!!!\n");
        }
        else
        {
            for (i = 0; i < BGImage->w; ++i)
            {
                for (j = 0; j < BGImage->h; ++j)
                {
                    dx = GetHMDXValue(&hm, i, j);
                    dy = GetHMDYValue(&hm, i, j);

                    if ( (dx != 0) || (dy != 0) )
                    {
                        x = BoundaryHandler( i+dx, 0,
                                             hm.Width-1, MODE);

                        y = BoundaryHandler( j+dy, 0,
                                             hm.Height-1, MODE);

                        PixBuf_BGImage
                        = (Uint8 *)BGImage->pixels
                          + (y * BGImage->pitch) + 3*x;

                        PixBuf_Screen
                        = (Uint8 *)Screen->pixels
                          + (j * Screen->pitch) + 3*i;

                        memcpy(PixBuf_Screen, PixBuf_BGImage, 3);
                    }
                }
            }

            SDL_UnlockSurface(Screen);

            /* This function should not be
             * called while screen is locked*/
            SDL_UpdateRects(Screen, 1, &dest);
        }


//#ifdef __NEEDDELAY__
        SDL_Delay(DELAYTIME);
//#endif

        /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
        /* message loop */
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_MOUSEBUTTONDOWN:
            {
                Mouse_X = event.button.x;
                Mouse_Y = event.button.y;
                MouseClickFlag = 1;
            }
            case SDL_KEYUP:
            {
                if (event.key.keysym.sym == SDLK_ESCAPE)
                {
                    goto QUITPOINT;
                }
                break;
            }
            case SDL_QUIT:
            {
                goto QUITPOINT;
                break; /* useless */
            }
            default:
            {
                /* doing nothing */
            }
            }
        }
    }


QUITPOINT:


    HeightMap_Release(&hm);
    return EXIT_SUCCESS;
}




/* EOF */


